package cate.game.play.base;

import cate.common.annotation.SplitParse;
import cate.common.table.d.GD;
import cate.common.table.d.GDAttr;
import cate.common.table.d.GDSkill;
import cate.common.util.SplitParser;
import cate.common.util.XT;
import cate.game.attr.FightAttr;
import cate.game.play.config.PlayCfgArgs;
import cate.game.play.fighter.Fighter;
import cate.game.play.util.FighterFilter;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;

import java.util.ArrayList;
import java.util.List;

@NoteClass("血量结算配置")
public class HpCfg {

	private PlayCfgArgs args;

	private List<Config> configs;

	private static final String DEFAULT_KEY = "血量配置";

	public HpCfg(PlayCfgArgs args) {
		parse(args, DEFAULT_KEY);
	}

	public HpCfg(PlayCfgArgs args, String key) {
		parse(args, key);
	}

	public void parse(PlayCfgArgs args, String key) {
		this.args = args;
		this.configs = SplitParser.parse(Config.class, this.args.get(key));
	}

	public HpCfg(byte attrSrc, int attrType, double coeff) {
		this.configs = new ArrayList<>();
		this.configs.add(new Config(attrSrc, attrType, coeff));
	}

	public void merge(HpCfg hpCfg){
		this.configs = XT.merge(configs, hpCfg.configs);
	}


	public boolean isEmpty(){
		return XT.isBlank(configs);
	}

	public double totalCeoff() {
		if (XT.isNotBlank(configs)) {
			return configs.stream().mapToDouble(c -> c.coeff).sum();
		}
		return 0d;
	}

	public static class Config{

		@NoteField("属性基准（即数值的依据是谁的属性）")
		@SplitParse(order = 0,defaultValue = "1")
		public byte attrSrc;

		@NoteField("属性（即数值的依据是哪个属性）")
		@SplitParse(order = 1,defaultValue = "2")
		public int attrType;

		@NoteField("系数")
		@SplitParse(order = 2,defaultValue = "0")
		public double coeff;

		@NoteField("偏移值")
		@SplitParse(order = 3,defaultValue = "0")
		public double offset;

		@NoteField("最大值属性基准（即数值的依据是谁的属性）")
		@SplitParse(order = 4,defaultValue = "0")
		public byte maxAttrSrc;

		@NoteField("最大值属性（即数值的依据是哪个属性）")
		@SplitParse(order = 5,defaultValue = "0")
		public int maxAttrType;

		@NoteField("最大值系数")
		@SplitParse(order = 6,defaultValue = "0")
		public double maxCoeff;


		public double calHpChange(FightAttr actorAttr, FightAttr targetAttr) {
			double hpChange = 0d;
			switch (attrSrc) {
				case GDSkill.Base.CASTER:
					hpChange = getValFromFighter(actorAttr, attrType, coeff);
					break;
				case GDSkill.Base.TARGET:
					hpChange = getValFromFighter(targetAttr, attrType, coeff);
					break;
				default:
					break;
			}
			hpChange += offset;
			if (maxAttrSrc > 0) {
				double max = calMax(actorAttr, targetAttr);
				if (max > 0) {
					hpChange = Math.min(hpChange, max);
				}
			}
			return hpChange;
		}

		private double calMax(FightAttr actorAttr, FightAttr targetAttr) {
			switch (maxAttrSrc) {
				case GDSkill.Base.CASTER:
					return getValFromFighter(actorAttr, maxAttrType, maxCoeff);
				case GDSkill.Base.TARGET:
					return getValFromFighter(targetAttr, maxAttrType, maxCoeff);
				default:
					return 0d;
			}
		}

		private static double getValFromFighter(FightAttr fightAttr, int attrType, double coef) {
			return fightAttr.getTotalValue(attrType) * coef / GD.W_10000_0;
		}

		public Config() {
		}

		public Config(byte attrSrc, int attrType, double coeff) {
			this.attrSrc = attrSrc;
			this.attrType = attrType;
			this.coeff = coeff;
		}

		@Override
		public String toString() {
			StringBuilder sb = new StringBuilder();
			sb.append(toHpStr(attrSrc,attrType,coeff));
			if (maxAttrSrc > 0) {
				sb.append("最大不超过");
				sb.append(toHpStr(maxAttrSrc, maxAttrType, maxCoeff));
			}
			return sb.toString();
		}

		private String toHpStr(byte src, int type, double coeff) {
			StringBuilder sb = new StringBuilder();
			sb.append("【");
			sb.append(GDSkill.Base.getName(src));
			sb.append("】【");
			sb.append(String.format("%1.0f", coeff / 100));
			sb.append("%】的【");
			sb.append(GDAttr.getKeyName(type));
			sb.append("】");
			return sb.toString();
		}
	}

	public double settle(Fighter actor, Fighter target) {
		return settle(actor, target, actor.attr.total(), target.attr.total());
	}


	public double settle(Fighter actor, Fighter target, FightAttr actorAttr, FightAttr targetAttr) {
		if (!FighterFilter.test(args, actor, target)) {
			return 0;
		}
		double total = 0d;
		if (XT.isNotBlank(configs)) {
			for (Config config : configs) {
				total += config.calHpChange(actorAttr, targetAttr);
			}
		}
		return total;
	}
}
